package code.ws_common_net.utils
{
	import code.ws_common_utils.Long;
	
	import flash.utils.ByteArray;

	public class ByteBuffer
	{
		/**默认长度*/
		public static const SIZE:int=32;
		/**默认最大长度*/
		public static const MAX_DATA_LEN:int=400*1024;
		/**字节数组*/
		protected var bytes:ByteArray;
		
		
		public function ByteBuffer(data:ByteArray=null)
		{
			if(data==null)
			{
				bytes=new ByteArray();
			}
			else
			{
				bytes=data;
			}
		}
		
		/** 得到字节缓存的长度 */
		public function  top():int
		{
			return this.bytes.length;
		}
		/** 设置字节缓存的长度 */
		public function  setTop(top:int):void
		{
			setCapacity(top);
			
		}
		public function getByteArray():ByteArray
		{
			return bytes;
		}
		public function setByteArray(data:ByteArray)
		{
			bytes=data;
		}
		/**字节缓存的大小*/
		public function capacity():int
		{
			return bytes.length;
		}
		public function setCapacity(len:int):void
		{
			var c:int=bytes.length;
			if(len<=c)return;
				bytes.length=len;
		}
		/**字节缓存的偏移量*/
		public function offset():int
		{
			return this.bytes.position;
		}
		public function setOffset(offest:int):void
		{
			if(this.bytes.position>capacity())return;
			this.bytes.position=offest;
		}
		/**字节缓存使用长度*/
		public function length():int
		{
			return this.bytes.bytesAvailable;
		}
		/**偏移量字节*/
		public function readAt(pos:int):Number
		{
			return bytes[pos] as Number;
		}
		public function writeAt(b:int,pos:int):void
		{
			bytes[pos]=b;
		}
		public function read(data:ByteArray,pos:int,len:int)
		{
			bytes.readBytes(data,pos,len);
		}
		/**   读数据
		 *    1 布尔值
		 *    2 字节
		 *    3 无符号字节
		 *    4 短整型数据
		 *    5 字符
		 *    6 无符号短整型数值
		 * 	  7 整型数值
		 * 	  8 浮点数值
		 * 	  9 长整型数值
		 * 	  10 双浮点数值
		 * 	  11 动态长度
		 * 	  12 指定长度的字节数组
		 * 	  13 短字节数组 长度不超过254
		 *    14 指定长度的字符串
		 *    15 短字符串 长度不超过254
		 * 	  16 字符串 长度不超过65534
		 * 	  17 指定长度和编码类型的字符串
		 * 	  18 指定长度的utf字符串
		 *    19 读出一个long
		 * */
		
		public function readBoolean():Boolean
		{
			return bytes.readBoolean();
		}
		public function readByte():int
		{
			return bytes.readByte();
		}
		public function readUnsignedByte():int
		{
			return bytes.readUnsignedByte();
		}
		public function readShort():int
		{
			return bytes.readShort();
		}
		public function readChar():String
		{
			return String.fromCharCode(readUnsignedShort());
		}
		public function readUnsignedShort():int
		{
			return bytes.readUnsignedShort();
		}
		public function readInt():int
		{
			return bytes.readInt();
		}
		public function readFloat():Number
		{
			return bytes.readFloat();
		}
		public function readLong():Number
		{
			return Long.readFrom(this.bytes).valueOf();
		}
		public function readDouble():Number
		{
			return this.bytes.readDouble();
		}
		public function readLength():int
		{
			var ns:int=this.bytes[this.bytes.position]&0xff;
			if(ns>=0x80)
			{
				this.bytes.position++;
				return ns-0x80;
			}
			else if(ns>=0x40)
				return readUnsignedShort()-0x4000;
			else if(ns>=0x20)
				return readInt()-0x20000000;
			else 
				throw new Error("error");
		}
		public function readData():ByteArray
		{
			var len:int=readLength()-1;
			if(len<0)return null;
			if(len>MAX_DATA_LEN)throw new Error("error");
			var data:ByteArray=new ByteArray();
			read(data,0,len);
			return data;
		}
		public function readShortData():ByteArray
		{
			var len:int=readUnsignedByte();
			if(len==255)return null;
			var data:ByteArray=new ByteArray();
			if(len!=0)read(data,0,len);
			return data;
		}
		public function readString(len:int):String
		{
			return this.bytes.readUTFBytes(len);
		}
		public function readShortString():String
		{
			var len:int=readUnsignedByte();
			if(len==255)return null;
			return readString(len);
		}
		public function readLongString():String
		{
			var len:int=readUnsignedShort();
			if(len==65535)return null;
			return readString(len);
		}
		public function  readMultiByte( charsetName:String):String
		{
			var len:int=readLength()-1;
			if(len<0) return null;
			if(len>MAX_DATA_LEN){
				throw new Error(this+" readUTF, data overflow:"+len);
			}
			return this.bytes.readMultiByte(len,charsetName)
		}
		public function readUTF():String
		{
			var len:int=readLength()-1;
			if(len<0) return null;
			if(len>MAX_DATA_LEN){
				throw new Error(this+" readUTF, data overflow:"+len);
			}
			return this.bytes.readUTFBytes(len);
		}
		public function readLocalLong():Long{
			return Long.readFrom(this.bytes)
		}
		
		
		public function write(data:ByteArray, pos:int=0, len:int=0):void
		{
			this.bytes.writeBytes(data,pos,len)
		}
		/**   写数据
		 *    1 布尔值
		 *    2 字节
		 *    3 字符
		 *    4 短整型数值
		 * 	  5 在指定位置写入一个短整型数值，length不变
		 *    6 整型数值
		 *    7 在指定位置写入一个整型数值，length不变 
		 * 	  8 浮点数值
		 * 	  9 长整型数值
		 *    10 长整型数值
		 *    11 双浮点数值
		 *    12 动态长度
		 *    13 一个字节数组，可以为null 
		 *    14 一个字节数组，可以为null
		 * 	  15 一个字符串，可以为null
		 *    16 一个字符串，以指定的字符进行编码
		 *    17 一个utf字符串，可以为null 
		 *    18 一个utf字符串中指定的部分，可以为null 
		 * */
		public function writeBoolean(b:Boolean):void
		{
			this.bytes.writeBoolean(b);
		}
		public function writeByte(b:int):void
		{
			this.bytes.writeByte(b)
		}
		public function writeChar(c:int):void
		{
			writeShort(c);
		}
		public function writeShort(s:int):void
		{
			this.bytes.writeShort(s)
		}
//		public function writeShort(s:int):void
//		{
//			this.bytes.writeShort(s)
//		}
		public function writeShortAt(s:int,pos:int):void
		{
			var tp:int=this.bytes.position
			this.bytes.position=pos
			this.bytes.writeShort(s);
			this.bytes.position=tp;
		}
		public function writeInt(i:int):void
		{
			this.bytes.writeInt(i);
		}
		public function writeIntAt(i:int,pos:int):void
		{
			var tp:int=this.bytes.position
			this.bytes.position=pos
			this.bytes.writeInt(i);
			this.bytes.position=tp;
		}
		public function writeFloat(f:Number):void
		{
			this.bytes.writeFloat(f);
		}
		public function writeLong(l:Number):void
		{
			var _l:Long =new Long(l)
			_l.writeTo(this.bytes)
		}
		public function writeLocalLong(l:Long):void{
			l.writeTo(this.bytes)
		}
		public function writeDouble(d:Number):void
		{
			this.bytes.writeDouble(d);
		}
		public function writeLength(len:int):void
		{
			if(len>=0x20000000||len<0)
				throw new Error(this+" writeLength, invalid len:"+len);
			if(len>=0x4000)
				writeInt(len+0x20000000);
			else if(len>=0x80)
				writeShort(len+0x4000);
			else
				writeByte(len+0x80);
		}
		public function writeData(data:ByteArray):void
		{
			writeDataAt(data,0,(data!=null)?data.length:0);
		}
		public function writeDataAt(data:ByteArray,pos:int,len:int):void
		{
			if(data==null)
			{
				writeLength(0);
				return;
			}
			writeLength(len+1);
			write(data,pos,len);
		}
		public function writeString(s:String):void
		{
			if(s!=null)
			{
				var temp:ByteArray=new ByteArray();
				temp.writeUTFBytes (s) 
				if(temp.length>65534)
					throw new Error(this+" writeString, invalid s:"+s);
				writeShort(temp.length);
				if(temp.length!=0) write(temp,0,temp.length);
			}
			else
				writeShort(65535);
		}
		public function writeMultiByte( str:String, charsetName:String):void
		{
			if(str==null)
			{
				writeLength(0);
				return;
			}
			var data:ByteArray=new ByteArray();
			if(charsetName!=null)
			{
				try
				{
					data.writeMultiByte(str,charsetName);
				}
				catch(e:Error)
				{
					throw new Error(e+" writeUTF, invalid charsetName:"+charsetName);
				}
			}
			else{
				data.writeUTFBytes(str);
			}
			writeLength(data.length+1);
			write(data,0,data.length);
		}
		public function writeUTF(str:String):void
		{
			writeUTFAt(str,0,(str!=null)?str.length:0);
		}
		
		public function writeUTFAt( str:String,index:int,length:int):void
		{
			if(str==null)
			{
				writeLength(0);
				return;
			}
			var data:ByteArray=new ByteArray();
			data.writeUTFBytes(str.slice(index,length));
			writeLength(data.length+1);
			write(data,0,data.length);
		}
		
		public function writeUTFBytes(str:String):void{
			bytes.writeUTFBytes(str);
		}
		
		/** 检查是否为相同类型的实例 */
		public function  checkClass( obj:Object):Boolean
		{
			return (obj is ByteBuffer);
		}
		/** 在指定位置写入一个字节，length不变 */
		public function writeByteAt(b:int,pos:int):void
		{
			var tp:int=this.bytes.position
			this.bytes.writeByte(b)
			this.bytes.position=tp
		}
		/** 得到字节缓存当前长度的字节数组 */
		public function toByteArray():ByteArray
		{
			var data:ByteArray =new ByteArray()
			data.writeBytes(bytes)
			return bytes;
		}
		/** 清除字节缓存对象 */
		public function clear():void
		{
			this.bytes.clear();
		}
		/* common methods */
		public function hashCode():int
		{
			var hash:int=17;
			for(var i:int=this.bytes.length-1;i>=0;i--)
				hash=65537*hash+bytes[i];
			return hash;
		}
		public function  equals( obj:Object):Boolean
		{
			if(this==obj) return true;
			if(obj is ByteBuffer) return false;
			var bb:ByteBuffer=obj as ByteBuffer;
			if(bb==null) return false;
			if(bb.top()!=this.bytes.length) return false;
			if(bb.offset()!=this.bytes.position) return false;
			for(var i:int=this.bytes.length-1;i>=0;i--)
			{
				if(bb.bytes[i]!=bytes[i]) return false;
			}
			return true;
		}
		
		public function  toString():String
		{
			return "["+this.bytes.length+","+this.bytes.position+"] ";
		}
		
		
	}
}